import Axios from 'axios'
import ModalApi from '@/components/SwModal/api.js'
import store from '@/store/index.js'
import codeHandles from './codeHandles.js'
import _ from '@/libs/lodash.min.js'
import Utils from '@/utils/Utils.js'
import hostConfig from './hostConfig.json'

const hosts = hostConfig[process.env.HTTP_ENV] // process.env.HTTP_ENV dev test preview production

function HTTP (opts) {
  // 以下配置在实例化时为必选项
  // 处理业务状态码
  this.codeHandles = {'201' () { alert('用户不存在') }}
  // 设置默认配置
  this.successCodes = '200'
  this.host = '//192.168.1.1'
  // 返回数据成功标志
  this.isOk = (res) => {
    return !!res // 例子
  }
  this.setDefaultConfig = () => {
    let defaultConfig = {
      headers: {}
    }
    // 例子 defaultConfig.headers['ClientType'] = '0'
    return defaultConfig
  }
  this.setParams = (params) => {
    return params
  }

  // http选项
  this.defOpts = {
    mock: '',
    isDisposeCode: true, // 是否处理状态码
    responseLevel: 'response.data', // 取接口响应数据层级
    isCustomUrl: false, // 是否是自定义的URL
    isQueryString: false, // 是否把参数放在url后面
    ignorableCodes: '', // 忽略某些状态码不进行处理，以,分隔
    isShowLoading: false,
    toCache: false, // 缓存
    fromCache: false, // 从缓存读取
    modalOptions: {}
  }

  this.caches = {}

  Object.assign(this, opts)
}
HTTP.prototype = {
  mergeConfig (opts = {config: {}}) {
    let defaultConfig = this.setDefaultConfig()
    let config = _.merge({}, defaultConfig, opts.config)
    return config
  },
  send (type, url, params = {}, opts = {}) {
    opts = Object.assign({}, this.defOpts, opts)

    let promise = Utils.makePromise()
    let ajaxUrl = opts.isCustomUrl ? url : this.host + '/api/' + url
    ajaxUrl = opts.mock ? `/static/mock/${opts.mock}.json` : ajaxUrl

    // 保存原params
    let oParams = Object.assign({}, params)

    // mock模式下，把参数放在url便于查看
    if (opts.isQueryString || opts.mock) {
      ajaxUrl += ('?' + this.getQueryString(params))
      params = {}
    }

    // 默认情况下Content-Type是x-www-form-urlencoded，其它情况则是json方式
    if (!(opts.config && opts.config.headers && opts.config.headers['Content-Type'])) {
      params = this.getQueryString(params)
    }

    // 合并config
    let config = this.mergeConfig(opts)

    // 忽略状态码
    if (opts.ignorableCodes) opts.ignorableCodes = (',' + opts.ignorableCodes.replace(/\s/g, '') + ',')

    // 加载中
    let loadingHandle
    if (opts.isShowLoading) {
      loadingHandle = ModalApi.loading({id: 'loading'})
    }

    // 若需要从读取cache则读取，否则发送请求，params必须是对象
    let cache = opts.fromCache && this.getCache(url, oParams, opts)
    let responsePromise
    if (cache) {
      responsePromise = cache
    } else {
      responsePromise = Axios({
        method: opts.mock ? 'get' : type,
        headers: config.headers,
        url: ajaxUrl,
        data: params
      }) // [opts.mock ? 'get' : type](ajaxUrl, params, config)
    }
    responsePromise.then((response) => {
      // 显示加载中
      if (opts.isShowLoading) {
        loadingHandle.close()
      }

      // 进行缓存
      // 记得要考虑一点：如果response是来自于上次chace的话，就没必要进行setCache，因为这样会进入无限缓存循环中导致无法再次请求
      opts.toCache && !cache && this.setCache(url, oParams, opts, response)

      // 处理状态码
      !opts.mock && this.disposeCode(response.data.StatusCode, opts, response.data)

      let res = this.getResponseByLevel(response, opts.responseLevel)
      // 用get请求回来的文本会报错所以用isObject
      _.isObject(res) && (res.isOk = this.isOk(response.data))
      // 激活调用的then
      promise.resolveHandle(res)
    })
    .catch((error) => {
      if (opts.isShowLoading) {
        loadingHandle.close()
      }
      if (opts.mock) return
      ModalApi.message(store.state.lang.lang['server busying'])
      // console.log(error)
    })

    return promise
  },
  post (url, params, opts) {
    return this.send('post', url, params, opts)
  },
  get (url, params, opts) {
    return this.send('get', url, params, opts)
  },
  getResponseByLevel (response, level = 'response.data') {
    response = { response }
    let need
    need = _.get(response, level)
    return need
  },
  disposeCode (code, opts, res) {
    // 要自动处理状态码，且状态码不为空，且不在忽略的状态码列表里
    if (opts.isDisposeCode && opts.ignorableCodes.indexOf(',' + code + ',') === -1 && code && !this.isOk(res)) {
      if (this.codeHandles[code]) {
        this.codeHandles[code](opts)
      } else {
        if (code !== '51077') {
          let msg = store.state.lang.lang[code] || code
          ModalApi.message(_.isObject(opts.modalOptions) ? _.assign(opts.modalOptions, {msg}) : msg)
        }
      }
    }
  },
  setCache (url, params, opts, response) {
    let tmp = {
      params,
      opts,
      response,
      time: +new Date()
    }
    // 每个url下，根据params的不同会生成不一样的cache
    if (this.caches[url]) {
      for (let i = 0; i < this.caches[url].length; i++) {
        if (_.isEqual(this.caches[url][i].params, params)) {
          this.caches[url][i] = tmp
          return
        }
      }
      this.caches[url].push(tmp)
    } else {
      this.caches[url] = [tmp]
    }
  },
  getCache (url, params, opts) {
    let response = null
    let cache
    // url相等且params相等
    if (this.caches[url]) {
      for (let i = 0; i < this.caches[url].length; i++) {
        cache = this.caches[url][i]
        // 找到了
        if (_.isEqual(cache.params, params)) {
          // 过期
          if (
            !_.isBoolean(cache.opts.toCache) &&
            +new Date() > (cache.time + this.getMillisec(cache.opts.toCache))
          ) {
            this.caches[url].splice(i, 1)
            break
          }
          response = cache.response
          break
        }
      }
    }
    return response ? Promise.resolve(response) : null
  },
  // str = 1s 2m 3h 10d
  getMillisec (str) {
    var unit = str.slice(-1)
    var value = str.slice(0, -1)
    if (unit === 's') {
      return value * 1000
    } else if (unit === 'm') {
      return value * 60 * 1000
    } else if (unit === 'h') {
      return value * 60 * 60 * 1000
    } else if (unit === 'd') {
      return value * 24 * 60 * 60 * 1000
    } else {
      return value
    }
  },
  getQueryString: (json = {}) => {
    var arr = []
    for (let key in json) {
      arr.push(key + '=' + json[key])
    }
    return arr.join('&')
  }
}

let defaultConfig = {
  host: '',
  successCodes: '200',
  isOk (res) {
    return res && (',' + this.successCodes + ',').indexOf(',' + res.StatusCode + ',') > -1
  },
  codeHandles: codeHandles,
  setDefaultConfig () {
    let defaultConfig = {
      headers: {}
    }
    defaultConfig.headers['token'] = store.state.user.userInfo.token || '' // 后台是以小写开头
    defaultConfig.headers['language-code'] = store.state.lang.langKey
    defaultConfig.headers['ClientType'] = '0'
    defaultConfig.headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'
    return defaultConfig
  },
  setParams (params) {
    // 默认是form data格式
    // return this.getQueryString(params)
  }
}

const Host1 = new HTTP(_.assign(defaultConfig, {
  host: hosts.host1
}))
const Http = Host1

const Host2 = new HTTP(_.assign(defaultConfig, {
  host: hosts.host2
}))

const Host3 = new HTTP(_.assign(defaultConfig, {
  host: hosts.host3
}))

const Host4 = new HTTP(_.assign(defaultConfig, {
  host: hosts.host4
}))

const install = (Vue) => {
  Vue.prototype.$http = Host1
  Vue.prototype.$host1 = Host1
  Vue.prototype.$host2 = Host2
  Vue.prototype.$host3 = Host3
  Vue.prototype.$host4 = Host4
  // 卢少鑫,获取币种图片API的前缀host
  Vue.prototype.currencyImgUrl = Host1.host + '/api/StaticContent/GetImages?fileName='
}

export {
  Http,
  Host1,
  Host2,
  Host3,
  Host4,
  hosts
}

export default install
